using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Animations;
using UnityEngine.Playables;


public class AnimCompoent : MonoBehaviour
{
    [SerializeField] List<AnimItem> animItemList = new();

    private Dictionary<string, AnimInfo> animInfoDic = new(animCount);
    private PlayableGraph playableGraph;
    private AnimationPlayableOutput animationPlayableOutput;
    private AnimationLayerMixerPlayable animationLayerMixerPlayable;

    private static int animCount = 100;//每层动画的预设数量, 可以大于实际数量, 不能小于实际数量
    public static int layerCount = 10;//动画的预设层数, 可以大于实际数量, 不能小于实际数量

    private Dictionary<uint, AnimLayer> animLayerDic = new();
    private List<AnimLayer> animLayerList = new();

    public Animator Animator { get; private set; }


    private void Update()
    {
        foreach (var animLayer in animLayerList)
        {
            animLayer.OnUpdate();
        }
    }
    private void OnDestroy()
    {
        if (playableGraph.IsValid()) playableGraph.Destroy();
    }

    public void Init(Animator animator, string name = null)
    {
        //初始化Playable
        if (animator == null) return;
        Animator = animator;
        if (playableGraph.IsValid()) playableGraph.Destroy();
        playableGraph = PlayableGraph.Create("PlayableGraph_" + name ?? animator.name);
        animationPlayableOutput = AnimationPlayableOutput.Create(playableGraph, "output", animator);

        //创建Layer分层Playable
        animationLayerMixerPlayable = AnimationLayerMixerPlayable.Create(playableGraph, layerCount);
        animationPlayableOutput.SetSourcePlayable(animationLayerMixerPlayable);

        //清空字典
        animInfoDic.Clear();
        animLayerDic.Clear();
        animLayerList.Clear();

        //初始化动画
        for (int i = 0; i < animItemList.Count; i++)
        {
            InitAnimation(animItemList[i].Key, animItemList[i].animClip);
        }
    }

    /// <summary>
    /// 加载动画进入Playable集合
    /// </summary>
    public void InitAnimation(string animKey, AnimationClip animationClip, uint layer = 0, bool Additive = false)
    {
        if (string.IsNullOrEmpty(animKey)) animKey = animationClip.name;
        if (animInfoDic.ContainsKey(animKey))
        {
            //Debug.LogError($"AnimKey重复了, key=={animKey}");
            return;
        }

        AnimationMixerPlayable animationMixerPlayable;

        if (!animLayerDic.ContainsKey(layer))
        {
            //创建混合Playable
            animationMixerPlayable = AnimationMixerPlayable.Create(playableGraph, animCount);
            playableGraph.Connect(animationMixerPlayable, 0, animationLayerMixerPlayable, (int)layer);
            animationLayerMixerPlayable.SetInputWeight((int)layer, 1);
            if (Additive)
            {
                animationLayerMixerPlayable.SetLayerAdditive(layer, true);
            }

            //初始化AnimLayer
            AnimLayer animLayer = new(this, playableGraph, animationMixerPlayable);
            animLayerDic.Add(layer, animLayer);
            animLayerList.Add(animLayer);
        }
        else
        {
            animationMixerPlayable = animLayerDic[layer].AnimationMixerPlayable;
        }

        //字典的长度作为动画索引
        int inputPort = animInfoDic.Count;
        AnimationClipPlayable animationClipPlayable = AnimationClipPlayable.Create(playableGraph, animationClip);
        playableGraph.Connect(animationClipPlayable, 0, animationMixerPlayable, inputPort);
        animationMixerPlayable.SetInputWeight(inputPort, 0);

        animInfoDic.Add(animKey, new AnimInfo()
        {
            inputPort = inputPort,
            CurrPlayable = animationClipPlayable,
        });
    }


    public AnimInfo PlayAnim(AnimationClip animClip, bool isLoop = false, float mixTime = 0.25f, uint layer = 0, Action onComplete = null)
    {
        return PlayAnim(animClip.name, isLoop, mixTime, layer, onComplete);
    }
    public AnimInfo PlayAnim(string animName, bool isLoop = false, float mixTime = 0.25f, uint layer = 0, Action onComplete = null)
    {
        if (animInfoDic.TryGetValue(animName, out AnimInfo roleAnimInfo))
        {
            if (animLayerDic.TryGetValue(layer, out AnimLayer animLayer))
            {
                animLayer.PlayAnimByInputPort(roleAnimInfo, onComplete, isLoop, mixTime);
            }
            else
            {
                Debug.LogError($"找不到动画Layer, animName=={animName}");
                onComplete?.Invoke();
            }
        }
        else
        {
            Debug.LogError($"找不到动画, animName=={animName}");
            onComplete?.Invoke();
        }
        return roleAnimInfo;
    }

    public void SetSpeed(float speed)
    {
        animationLayerMixerPlayable.SetSpeed(speed);
    }


    public class AnimLayer
    {
        private PlayableGraph playableGraph;

        private Coroutine CoroutineDelayAnim;

        private float m_Mix;

        //两个动画过度的时间
        private float m_CurrentMixTime;
        private int m_CurrAnimId;
        private int m_OldAnimId;

        private MonoBehaviour monoBehaviour;

        public AnimationMixerPlayable AnimationMixerPlayable { get; private set; }

        public AnimLayer(MonoBehaviour monoBehaviour, PlayableGraph playableGraph, AnimationMixerPlayable animationMixerPlayable)
        {
            this.monoBehaviour = monoBehaviour;
            this.playableGraph = playableGraph;
            this.AnimationMixerPlayable = animationMixerPlayable;
        }
        public void OnUpdate()
        {
            //混合动画更新, 动画过度 从0到1
            if (m_Mix < 1)
            {
                m_Mix += Time.deltaTime / m_CurrentMixTime;
                m_Mix = Mathf.Min(1, m_Mix);
                AnimationMixerPlayable.SetInputWeight(m_OldAnimId, 1f - m_Mix);
                AnimationMixerPlayable.SetInputWeight(m_CurrAnimId, m_Mix);
            }
        }

        public void PlayAnimByInputPort(AnimInfo roleAnimInfo, Action onComplete, bool isLoop, float mixTime)
        {
            m_CurrentMixTime = mixTime;

            playableGraph.Play();

            Playable playable = AnimationMixerPlayable.GetInput(roleAnimInfo.inputPort);
            playable.SetTime(0);
            playable.Play();

            //把动画重置一下, 这个不是上一个动画 而是上上个动画了
            AnimationMixerPlayable.SetInputWeight(m_OldAnimId, 0);

            //这个是上一个动画
            m_OldAnimId = m_CurrAnimId;
            AnimationMixerPlayable.SetInputWeight(m_OldAnimId, 0);

            //这个是当前动画
            m_CurrAnimId = roleAnimInfo.inputPort;
            if (m_CurrAnimId == m_OldAnimId || m_OldAnimId == 0)
            {
                //当前动画和上一个动画是同一个动画, 不需要过度
                AnimationMixerPlayable.SetInputWeight(m_CurrAnimId, 1);
            }
            else
            {
                //不是同一个动画, 触发过度
                m_Mix = 0;
                AnimationMixerPlayable.SetInputWeight(m_OldAnimId, 1);
            }

            IEnumerator DelayAnim()
            {
                yield return new WaitForSeconds(roleAnimInfo.CurrPlayable.GetAnimationClip().length);
                if (!isLoop)
                {
                    playable.Pause();
                    onComplete?.Invoke();
                }
            }
            if (CoroutineDelayAnim != null) monoBehaviour.StopCoroutine(CoroutineDelayAnim);
            CoroutineDelayAnim = monoBehaviour.StartCoroutine(DelayAnim());
        }

    }

    public class AnimInfo
    {
        public int inputPort;
        public AnimationClipPlayable CurrPlayable;
    }

    [Serializable]
    public class AnimItem
    {
        public string Key;
        public AnimationClip animClip;
    }

}